package jdklearning.concurrent.thread;


import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;


public class ProducerAndConsumerTest {
	
	public static void main(String[] args) {
		ProducerAndConsumerTest threadTest1 = new ProducerAndConsumerTest();
		
		System.out.println("How to use wait and notify method in Java");
		System.out.println("Solving Producer Consumper Problem");
		Queue<Integer> buffer = new LinkedList<>();
		int maxSize = 10;
		Producer producer = threadTest1.new Producer(buffer, maxSize, "PRODUCER");
		Consumer consumer = threadTest1.new Consumer(buffer, maxSize, "CONSUMER");
		producer.start(); 
		consumer.start(); 
//		ConfigurationClassPostProcessor 
	}
	
	
	
	/**
	    * Producer Thread will keep producing values for Consumer
	    * to consumer. It will use wait() method when Queue is full
	    * and use notify() method to send notification to Consumer
	    * Thread.
	    *
	    * @author WINDOWS 8
	    *
	    */
	class Producer extends Thread{
		private Queue<Integer> queue;
		private int maxSize;
		public Producer(Queue<Integer> queue, int maxSize, String name){
			super(name); 
			this.queue = queue; 
			this.maxSize = maxSize;
		}
		
		@Override
		public void run() {
			while (true) {
				synchronized (queue) {
					while(queue.size() == maxSize) {
						System.out .println("Queue is full, " + "Producer thread waiting for " + "consumer to take something from queue");
						try {
							queue.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						Random random = new Random();
						int i = random.nextInt();
						System.out.println("Producing value : " + i);
						queue.add(i); 
						queue.notifyAll();
					}
				}
			}
		}
	}


	/**
	    * Consumer Thread will consumer values form shared queue.
	    * It will also use wait() method to wait if queue is
	    * empty. It will also use notify method to send
	    * notification to producer thread after consuming values
	    * from queue.
	    *
	    * @author WINDOWS 8
	    *
	    */
	class Consumer extends Thread{
		private Queue<Integer> queue;
		private int maxSize;
		public Consumer(Queue<Integer> queue, int maxSize, String name){
			super(name);
			this.queue = queue;
			this.maxSize = maxSize;
		}
		
		@Override 
		public void run() {
			while (true) {
				synchronized (queue) {
					while (queue.isEmpty()) {
						System.out.println("Queue is empty," + "Consumer thread is waiting" + " for producer thread to put something in queue");
						try {
							queue.wait();
						} catch (Exception ex) {
							ex.printStackTrace();
						}
					}
					System.out.println("Consuming value : " + queue.remove()); 
					queue.notifyAll();
				}
			}
		}
	
	}
	
}


